  SpannableString，相较于普通String带有丰富的格式设置，可使文本的可读性更强。两者都用于存储字符串，
而SpannableString的特殊之处就在于有一个setSpan()函数，因而能给存储的文本添加各种样式，诸如文本颜色样式((ForgroundColorSpan)，
文本背景颜色样式((BackgroundColorSpan)，下划线样式((UnderlineSpan)等，而今天我们的功能实现需要用到的则是图片样式(ImageSpan)。

       SpannableStringBuilder，类似于StringBuilder，可以通过其append()方法拼接多个String。而SpannableString则类似于String，
构造对象对传入一个String，之后再也无法更改String的内容，也无法拼接多个SpannableString。

实现

主要就是实现自定义控件类，然后覆写setText()方法
package com.example.emodemo.view;
 
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.widget.TextView;
 
public class EmoticonsTextView extends TextView {
 
    public EmoticonsTextView(Context context) {
        super(context);
    }
 
    public EmoticonsTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
 
    public EmoticonsTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
 
    @Override
    public void setText(CharSequence text, BufferType type) {
        if (!TextUtils.isEmpty(text)) {
            super.setText(replace(text.toString()), type);
        } else {
            super.setText(text, type);
        }
    }
 
    private Pattern buildPattern() {
        return Pattern.compile("\\[f[0-9]{3}]", Pattern.CASE_INSENSITIVE);
    }
 
    private CharSequence replace(String text) {
        try {
            SpannableString spannableString = new SpannableString(text);
            int start = 0;
            Pattern pattern = buildPattern();
            Matcher matcher = pattern.matcher(text);
            while (matcher.find()) {
                String faceText = matcher.group();
                String key = faceText.substring(1);
                key = key.substring(key.indexOf("[")+1, key.indexOf("]"));
                BitmapFactory.Options options = new BitmapFactory.Options();
                Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(),
                        getContext().getResources().getIdentifier(key, "drawable", getContext().getPackageName()), options);
                ImageSpan imageSpan = new ImageSpan(getContext(), bitmap);
                int startIndex = text.indexOf(faceText, start);
                int endIndex = startIndex + faceText.length();
                if (startIndex >= 0)
                    spannableString.setSpan(imageSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                start = (endIndex - 1);
            }
            return spannableString;
        } catch (Exception e) {
            return text;
        }
    }
}
 
 这里重点解析replace(String text)方法：
1.SpannableString spannableString = new SpannableString(text);
构建SpannableString对象，传入一个String(可以是纯文本，可以是表情代码，也可以是文本和表情代码混合)；
2Pattern pattern = buildPattern();
private Pattern buildPattern() {
        return Pattern.compile("\\[f[0-9]{3}]", Pattern.CASE_INSENSITIVE);
    }

将给定的正则表达式编译并赋予给Pattern类。这里你可以理解为制定了表情代码的正则表达式，文本中符合这个正则表达式的都是表情代码，即制定了一个筛选规则，用于筛选出文本中的表情代码。

这里的正则表达式含义为[f(连续三位0-9的整数)]，如[f001]，[f002]，[f003]等。

3.
Matcher matcher = pattern.matcher(text);
 生成一个给定命名的Matcher对象。你可以把这段代码理解为，是将上面制定的筛选规则输入了一台筛选机器，然后等待筛选。

4.while (matcher.find()) {
	尝试在目标字符串里查找下一个匹配子串。即进行遍历筛选，如果找到匹配子串，则会返回true；
5.String faceText = matcher.group()
返回当前查找而获得的与组匹配的子串内容。即取得筛选出的表情代码。
6.
key = key.substring(key.indexOf("[")+1, key.indexOf("]"));
取得"["和"]"内表情代码对应的资源命名，之后就通过该资源名在drawable文件夹中找到对应的图片资源，解析为Bitmap对象：

BitmapFactory.Options options = new BitmapFactory.Options();
				Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(),
					getContext().getResources().getIdentifier(key, "drawable", getContext().getPackageName()), options);

7
	ImageSpan imageSpan = new ImageSpan(getContext(), bitmap);
	int startIndex = text.indexOf(faceText, start);
      int endIndex = startIndex + faceText.length();
		传入Bitmap参数，构建ImageSpan对象。然后取得该表情代码在完整字符串中的起始索引和结束索引，即计算该表情的插入位置。
		之后即可调用setSpan()方法将文本中的表情代码替换为表情图片了。
8
spannableString.setSpan(imageSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);   

这里的第四个参数flag用于控制行为，取值包括如下：

Spannable.SPAN_EXCLUSIVE_EXCLUSIVE：前后都不包括，即在指定范围的前面和后面再插入新字符都不会应用该样式 
Spannable.SPAN_EXCLUSIVE_INCLUSIVE：前面不包括，后面包括。即仅在范围字符的后面再插入新字符时才会应用该样式
Spannable.SPAN_INCLUSIVE_EXCLUSIVE：前面包括，后面不包括。
Spannable.SPAN_INCLUSIVE_INCLUSIVE：前后都包括。


源码

http://download.csdn.net/detail/alfred_c/9140067

参考

http://blog.csdn.net/harvic880925/article/details/38984705

http://www.bmob.cn	
					























